package com.java.thread.practice;

/**
 * 经典例题：生产者和消费着问题
 * <p>
 * 生产者( Productor)将产品交给店员( Clerk),
 * 而消费者( (Customer)从店员处取走产品,
 * 店员一次只能持有固定数量的产品(比如:20),
 * 如果生产者试图生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;
 * 如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。
 */
class ProductTest {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();
        Producer p1 = new Producer(clerk);
        Producer p2 = new Producer(clerk);
        p1.setName("生产者1");
        p2.setName("生产者2");

        Consumer c1 = new Consumer(clerk);
        Consumer c2 = new Consumer(clerk);
        c1.setName("消费者1");
        c2.setName("消费者2");

        p1.start();
        c1.start();
    }
}

/**
 * 店员
 */
class Clerk {
    private int productNum;     // 商品数量

    public Clerk() {
        this.productNum = 0;
    }

    public int getProductNum() {
        return productNum;
    }

    public void setProductNum(int productNum) {
        this.productNum = productNum;
    }
}

/**
 * 生产者
 */
class Producer extends Thread {
    private Clerk clerk;

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "开始生产......");

        while(true){
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            produce();
        }
    }

    public Producer(Clerk clerk) {
        if (clerk != null) {
            this.clerk = clerk;
        }
    }

    private void produce() {
        synchronized (ProductTest.class) {
            ProductTest.class.notify();
            if (clerk.getProductNum() < 20) {
                clerk.setProductNum(clerk.getProductNum() + 1);
                System.out.println(Thread.currentThread().getName() + ":\t生产完成第 " + clerk.getProductNum() + " 个产品");
            }else {
                try {
                    ProductTest.class.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

/**
 * 消费者
 */
class Consumer extends Thread {
    private Clerk clerk;

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "开始消费......");

        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            buy();
        }
    }

    public Consumer(Clerk clerk) {
        if (clerk != null) {
            this.clerk = clerk;
        }
    }

    private void buy(){
        synchronized (ProductTest.class) {
            ProductTest.class.notify();
            if (clerk.getProductNum() > 0) {
                System.out.println(Thread.currentThread().getName() + ":\t购买完成第 " + clerk.getProductNum() + " 个产品");
                clerk.setProductNum(clerk.getProductNum() - 1);
            }else {
                try {
                    ProductTest.class.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
